package org.dbp;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.commons.lang3.StringUtils;
import org.dbp.anotacion.CampoVistaDbp;
import org.dbp.bean.CampoVista;

public  class TagDbpUtils { // NOPMD by linuxdavid on 9/06/13 1:53

	private static String plantillaEtiqueta="%s.campo.%s";
	


	/**
	 * 
	 * Nos devuelve la informacion de los campos de la capa de vista de la entidad que nos pasa.
	 * 
	 * Nota: Para configurarlos usaremos la anotacion CampoVistaDbp.
	 * 
	 * @param entidad	
	 * @return
	 */
	public static <T extends Serializable> List<CampoVista> obtenerLosCamposDeLaVista(final T entidad){
		List<CampoVista> valdev=null; // NOPMD by linuxdavid on 9/06/13 1:53
		if(entidad!=null){
			valdev= obtenerLosCamposDeLaVista(entidad.getClass());
		}
		return valdev;		
	}
	
	/**
	 * 
	 * Nos devuelve la informacion de los campos de la capa de vista de la entidad que nos pasa.
	 * 
	 * Nota: Para configurarlos usaremos la anotacion CampoVistaDbp.
	 * 
	 * @param claseEntidad	
	 * @return
	 */
	public static <T extends Serializable> List<CampoVista> obtenerLosCamposDeLaVista(final Class<T> claseEntidad){
		return cargarLosCamposVistaDesdeLosField(claseEntidad,
				ordenarLosCampos(
						ReflectionDbpUtils.getInstancia().obtenemosLosCamposDeUnaClase(claseEntidad,CampoVistaDbp.class)
						)
				);
	}
	

	/**
	 * Se encarga de cargar los campos que hemos obtenido de la reflexion en la lista de campos de vista 
	 * que vamos a necesitar.
	 * 
	 * @param entidad	Es la clase de la entidad con la que vamos a trabajar.
	 * @param campos	La lista de campos que nos ha llegado desde la reflexi�n.
	 * @return
	 */
	private static <T extends Serializable> List<CampoVista>  cargarLosCamposVistaDesdeLosField(
			final Class<T> entidad ,final List<Field> campos) {
		final List<CampoVista> valdev=new ArrayList<CampoVista>();
		CampoVistaDbp anotacion;
		for(Field campo:campos){
			anotacion=campo.getAnnotation(CampoVistaDbp.class);
			if(anotacion!=null){
				valdev.add(cargarElCampoDeLaVista(entidad, anotacion, campo));
			}
		}
		return valdev;
	}
	/**
	 * 
	 * Se encarga de cargar los datos de la vista, para lo cual nos basaremos en los datos de la reflexión del campo en JAVA +
	 * la anotación.
	 * 
	 * @param claseEntidad	Es la clase de la entidad con la que trabajamos.
	 * @param anotacion		Es la anotación con la que vamos a trabajar (Tiene la posición y la etiqueta).
	 * @param campo			Es el campo	que obtenemos de la reflexión.
	 * @return	Nos devuelve el campo
	 */
	private static <T extends Serializable> CampoVista cargarElCampoDeLaVista(
			final Class<T> claseEntidad,final CampoVistaDbp anotacion,final Field campo) {
		CampoVista elemento;
		elemento=new CampoVista();
		elemento.setPath(campo.getName());
		elemento.setTipo(campo.getType().getSimpleName());
		elemento.setEtiqueta(procesarLaEtiqueta(claseEntidad, anotacion, campo));
		return elemento;
	}
	/**
	 * 
	 * La etiqueta se cargara con el dato de la anotación, salvo que que este vacio en cullo caso,
	 * sera el <nombre de la clase>.campo.<nombre del campo>; 
	 *
	 *  Nota: La etiqueta es lo que va a ver el usuario.
	 *  
	 * @param claseEntidad	Es la clase de la entidad con la que trabajamos.
	 * @param anotacion		Es la anotación con la que vamos a trabajar (Tiene la posición y la etiqueta).
	 * @param campo			Es el campo	que obtenemos de la reflexión.
	 * @return	Nos devuelve la etiqueta.
	 */
	private static <T extends Serializable> String procesarLaEtiqueta(final Class<T> claseEntidad
			,final CampoVistaDbp anotacion,final Field campo){
		String valdev=anotacion.etiqueta();
		if(StringUtils.isBlank(valdev)){
			valdev=String.format(plantillaEtiqueta
					,StringUtils.uncapitalize(claseEntidad.getSimpleName())
					,campo.getName());
		}
		return valdev;
	}
	
	/**
	 * Este método se encarga de ordenar los campos por la posiciíon puesta en la anotación.
	 * @param campos
	 * @return
	 */
	private static List<Field> ordenarLosCampos(final List<Field> campos){
		return pasarDelArbolAUnaLista(cargarArbol(campos));
	}
	
	
	/**
	 * Nos pasa los campos de una estructura de map a una lista.
	 * @param ordenarCampo
	 * @return
	 */
	private static List<Field>  pasarDelArbolAUnaLista(final Map<Integer, Field> ordenarCampo) {
		final List<Field> valdev = new ArrayList<Field>();
		for(Field campo:ordenarCampo.values()){
			valdev.add(campo);
		}
		return valdev;
	}
	
	/**
	 * 
	 * Se encarga de cargar el arbol, con los campos ordenados con la posición.
	 * 
	 * @param campos	Los campos que vamos a ordenar, por el arbol.
	 * @return
	 */
	private static Map<Integer, Field> cargarArbol(final List<Field> campos) {
		final Map<Integer,Field> ordenarCampo = new TreeMap<Integer,Field>();
		CampoVistaDbp anotacion=null; // NOPMD by linuxdavid on 9/06/13 1:53
		for(Field campo:campos){
			anotacion=campo.getAnnotation(CampoVistaDbp.class);
			if(anotacion!=null){
				ordenarCampo.put(anotacion.posicion(), campo);
			}
		}
		return ordenarCampo;
	}
	
	
	
}
